Adds Linear, Miro, and Webflow web providers#2284
Adds Linear, Miro, and Webflow web providers#2284kevinchalet merged 9 commits intoopeniddict:devfrom
Conversation
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs
Outdated
Show resolved
Hide resolved
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
Show resolved
Hide resolved
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs
Show resolved
Hide resolved
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml
Outdated
Show resolved
Hide resolved
kevinchalet
left a comment
There was a problem hiding this comment.
Looks great, thanks for your PR, @jerriep! ❤️
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml
Outdated
Show resolved
Hide resolved
| // Miro uses a JSON payload that expects the "accessToken", "clientId", and "clientSecret" properties | ||
| else if (context.Registration.ProviderType is ProviderTypes.Miro) | ||
| { | ||
| context.Request["accessToken"] = context.Token; |
There was a problem hiding this comment.
Since you're going to send the access token in the Authorization header, there's no real point mapping it here. And if you don't nullify context.Request.Token here, you can reuse the same branch as the Zendesk provider in the AttachBearerAccessToken handler 😃
There was a problem hiding this comment.
Miro requires both the accessToken property in the JSON payload and the Bearer token. If I send just the Bearer token without the accessToken property, I get an error:
Likewise, if I omit the Bearer token and send just the accessToken property, it fails as well:
I need to supply both to get a successful response:
There was a problem hiding this comment.
Ah yeah, I thought that branch was for the Linear provider... that uses a single access_token parameter 🤣
| else if (context.Registration.ProviderType is ProviderTypes.Miro) | ||
| { | ||
| context.Request["accessToken"] = context.Token; | ||
| context.Request["clientId"] = context.Request.ClientId; |
There was a problem hiding this comment.
Interesting, I don't see these parameters mentioned in https://developers.linear.app/docs/oauth/authentication#id-6.-revoke-an-access-token. Are we sure their non-standard revocation endpoint supports client authentication?
There was a problem hiding this comment.
Yeah, Linear is an interesting one. Before I updated the parameters according to their docs, I tested the revocation and it worked:
So, in the initial PR, I did not make the code changes according to their docs. But, it is clearly risky doing this as it is not documented to work this way, and they can easily change it in the future so it does not work correctly anymore.
I have now updated the code to conform to their docs:
| // In the case of Miro, we renamed the Token to accessToken, so we cannot use the Token property. | ||
| else if (context.Registration.ProviderType is ProviderTypes.Miro) | ||
| { | ||
| if (context.Request.TryGetParameter("accessToken", out var parameter) && parameter.GetRawValue() is string accessToken) |
There was a problem hiding this comment.
You'll be able to remove that branch so it's not really important, but FYI, using GetRawValue() is discouraged as there's no absolute guarantee a parameter will be backed by a CLR string value: here, we use context.Request["accessToken"] = context.Token earlier, so it may indeed be backed by a string, but a custom event handler registered by the user could change that to say, a JsonValue representing a string:
context.Request["accessToken"] = JsonValue.Create(context.Token);It's better to always use the conversion operators so that the OpenIddictParameter structure gives you the correct target type independently of its backing CLR type:
var token = (string?) context.Request["access_token"];
if (!string.IsNullOrEmpty(token))
{
request.Headers.Authorization = new AuthenticationHeaderValue(Schemes.Bearer, token);
}... or if you prefer the minimally-indented version... 😄
else if (context.Registration.ProviderType is ProviderTypes.Miro &&
(string?) context.Request["access_token"] is { Length: > 0 } token)
{
request.Headers.Authorization = new AuthenticationHeaderValue(Schemes.Bearer, token);
}There was a problem hiding this comment.
Since both the accessToken property in the JSON payload, as well as the Bearer token are required, I fixed this code as per your suggestion.
|
Note: if we can merge this PR this week, I'll make sure it's included in the 6.2.0 release 😃 |
|
Hey @kevinchalet, I believe I addressed all the points you raised. I also picked up that the Miro and Webflow nameidentifier claim was not resolving correctly, so I fixed that as well. I did a final test of each provider doing the authorization and revocation and everything works as expected. Please review again |
| context.Request.ClientId = null; | ||
| context.Request.ClientSecret = null; |
There was a problem hiding this comment.
It works just fine, but there's actually a cleaner way to solve this problem: letting OpenIddict know that the revocation endpoint doesn't support client authentication so that it doesn't even attach the credentials to the request.
For that, you'll just need to add <RevocationEndpointAuthMethod Value="none" /> under the provider configuration (if you get a XML schema warning telling you the none value isn't allowed, you can rebase your branch, I tweaked the schema yesterday to allow all supported values).
<Configuration AuthorizationEndpoint="https://linear.app/oauth/authorize"
TokenEndpoint="https://api.linear.app/oauth/token"
RevocationEndpoint="https://api.linear.app/oauth/revoke"
UserInfoEndpoint="https://api.linear.app/graphql">
<RevocationEndpointAuthMethod Value="none" />
</Configuration>If you do that, you should be able to merge that else if branch with the previous one.
There was a problem hiding this comment.
I added the <RevocationEndpointAuthMethod Value="none" /> and merged the logic branch with the previous one. That caused the client_secret not to be sent, but it still sent the client_id.
So, I decided to keep the Linear logic in its own branch and clear the client_id by explicitly setting ClientId to null.
Looks great. Just a minor improvement remaining and it should be good to merge 😃 |
- Adds additional Miro claims for team and organization - Resolves Miro and Webflow nameidentifier claim correctly - Sorts Linear UserFields values alphabetically in XML file - Fixes incorrect use of OpenIddictParameter.GetRawValue() - Sends documented parameters to Linear token revocation endpoint
4c5b4af to
50f538c
Compare
|
I did another final run through the authorization and revocation flow for all three providers and everything still works. This PR should be good to go. |
|
Merged, thanks for your contribution! ❤️ (I'll backport your PR to 6.2.0 and release it later today) |







This adds the web providers for Linear, Miro, and Webflow.
Linear
Miro
Webflow